package it.unibo.refolding.pico.mfp;

import it.unimi.dsi.fastutil.ints.IntList;

import java.nio.ByteBuffer;
import java.util.Objects;

class BinHeader5 extends BinHeader {

  final int formulaSize; // The size of the dependency formula, if any.
  final int dataEUnitsSize; // The size of optional extended data units.
  final IntList dimEUnitsSize; // The size of optional
                               // extended dimension units.
  final IntList dimLabelsSize; // The size of optional
                               // dimension labels.
  final int sIndicesSize; // The size of string indices if this is a text wave.
  
  /**
   * @param checksum
   *          Makes the total checksum disappear.
   * @param wfmSize The size of the WaveHeader data structure plus the wave data.
   * @param formulaSize
   * @param noteSize
   * @param dataEUnitsSize
   * @param dimEUnitsSize
   * @param dimLabelsSize
   * @param sIndicesSize
   */
  public BinHeader5(short checksum, int wfmSize, int formulaSize, int noteSize, int dataEUnitsSize,
    IntList dimEUnitsSize, IntList dimLabelsSize, int sIndicesSize) {
    super(checksum, wfmSize, noteSize);
    this.formulaSize = formulaSize;
    this.dataEUnitsSize = dataEUnitsSize;
    this.dimEUnitsSize = dimEUnitsSize;
    this.dimLabelsSize = dimLabelsSize;
    this.sIndicesSize = sIndicesSize;
  }

  static Checksummed<BinHeader5> read(ByteBuffer bb) {
    int startPos = bb.position();
    int unsignedChecksum = 0;
    short checksum = bb.getShort();
    unsignedChecksum = IgorUtil.addShort(checksum, unsignedChecksum);
    int wfmSize = bb.getInt();
    unsignedChecksum = IgorUtil.addInt(wfmSize, unsignedChecksum);
    int formulaSize = bb.getInt();
    unsignedChecksum = IgorUtil.addInt(formulaSize, unsignedChecksum);
    int noteSize = bb.getInt();
    unsignedChecksum = IgorUtil.addInt(noteSize, unsignedChecksum);
    int dataEUnitsSize = bb.getInt();
    unsignedChecksum = IgorUtil.addInt(dataEUnitsSize, unsignedChecksum);
    IntList dimEUnitsSize = IgorUtil.readInts(IgorUtil.MAXDIMS, bb);
    unsignedChecksum = IgorUtil.addInts(dimEUnitsSize, unsignedChecksum);
    IntList dimLabelsSize = IgorUtil.readInts(IgorUtil.MAXDIMS, bb);
    unsignedChecksum = IgorUtil.addInts(dimLabelsSize, unsignedChecksum);
    int sIndicesSize = bb.getInt();
    unsignedChecksum = IgorUtil.addInt(sIndicesSize, unsignedChecksum);
    /*
     * Skip: int optionsSize1; // Reserved. Write zero. Ignore on read. int
     * optionsSize2; // Reserved. Write zero. Ignore on read.
     */
    unsignedChecksum = IgorUtil.skip(2 * 4, unsignedChecksum, bb);
    assert startPos + byteCount() == bb.position();
    return new Checksummed<>(new BinHeader5(
      checksum, wfmSize, formulaSize, noteSize, dataEUnitsSize, dimEUnitsSize, dimLabelsSize,
      sIndicesSize), (short) unsignedChecksum);
  }

  static int byteCount() {
    return BinHeader.byteCount() + 4 * 2 + 2 * IgorUtil.MAXDIMS * 4 + 4 + 8;
  }

  @Override
  public int hashCode() {
    return Objects.hash(
      checksum, wfmSize, formulaSize, noteSize, dataEUnitsSize, dimEUnitsSize, dimLabelsSize,
      sIndicesSize);
  }
}
